<template>
  <div>
    <canvas id="canvas" style="width: 300px;border: 1px solid red;"></canvas>
  </div>
</template>

<script>
import image from '@/assets/1.jpg'
import opacity from '@/assets/opacity.png'
import opacity1 from '@/assets/opacity1.png'

export default {
  name: 'CanvasOperate',
  data() {
    return {
      image: image,
      opacity: opacity
    }
  },
  mounted() {
    /* let i = 0
    const Timer = setInterval(() => {
      i++
      this.init(
        {
          imageUrl: 'https://shejimao-test.oss-cn-huhehaote.aliyuncs.com/template/3894677435564096/images/fbae108f-7aa9-3528-9eab-2bc326c651f1.png?time=' + new Date().valueOf(),
          width: 482,
          height: 589,
          imgWidth: 482,
          imgHeight: 529,
          left: 0, top: 0
        },
        'shadow',
        {
          shadow: {
            dx: 20,
            dy: 35,
            blur: 10,
            color: 'red'
          }
        })
      if (i > 1) {
        clearInterval(Timer)
      }
    })*/
    // 投影测试
    /*  this.init({ imageUrl: image, width: 428, height: 400, imgWidth: 695, imgHeight: 649, left: -100, top: -100 }, 'shadow', {
      shadow: {
        dx: 10,
        dy: 10,
        blur: 20,
        color: 'red'
      }
    }) */
    // 渐变测试
    /* this.init({ imageUrl: opacity1, width: 695, height: 649, imgWidth: 695, imgHeight: 649, left: 0, top: 0 }, 'gradient', {
      gradient: {
        type: 'linear',
        colors: ['blue', 'red'],
        positions: [0, 100],
        direction: -90
      }
    })*/
    // 纹理测试
    /* this.init({ imageUrl: opacity1, width: 695, height: 649, imgWidth: 695, imgHeight: 649, left: 0, top: 0 }, 'texture', {
       texture: {
         mode: 'repeat',
         uri: 'https://st0.dancf.com/02/material_uploader/202010120632-bbd5.jpg?x-oss-process=image/resize,w_132,h_132,m_fill/interlace,1,image/format,webp'
       }
     })*/
    // 投影加渐变
    /* this.init({ imageUrl: opacity1, width: 695, height: 649, imgWidth: 695, imgHeight: 649, left: 0, top: 0 }, 'shadowGradient', {
     shadow: {
       dx: -10,
       dy: -10,
       blur: 100,
       color: 'red'
     },
     gradient: {
       type: 'linear',
       colors: ['blue', 'red'],
       positions: [0, 100],
       direction: -90
     }
   })*/
    // 描边测试
   /* const url = 'https://st0.dancf.com/02/material_uploader/202010150436-5543.png'
    this.init({
      imageUrl: url,
      width: 800,
      height: 800,
      imgWidth: 800,
      imgHeight: 800,
      top: 0,
      left: 0
    }, 'strokeAll', {
      stroke: {
        type: '', // outer
        width: 10,
        color: '#3eef00'
      },
       shadow: {
        dx: 10,
        dy: 10,
        blur: 100,
        color: 'red'
      },
       gradient: {
        type: 'linear',
        colors: ['blue', 'red'],
        positions: [0, 100],
        direction: -90
      },
     /!* texture: {
        mode: 'repeat',
        uri: 'https://st0.dancf.com/02/material_uploader/202010120632-bbd5.jpg?x-oss-process=image/resize,w_132,h_132,m_fill/interlace,1,image/format,webp'
      }*!/
    })*/

   /* const mask = 'https://st-gdx.dancf.com/gaodingx/8/design/20180709-210808-a15f.png'
    const url = 'https://st0.dancf.com/02/material_uploader/202010150436-5543.png'
    this.init({
      imageUrl: url,
      width: 800,
      height: 800,
      imgWidth: 800,
      imgHeight: 800,
      top: 0,
      left: 0
    }, 'gradient', {
      gradient: {
        type: 'linear',
        colors: ['blue', 'red'],
        positions: [0, 100],
        direction: -90
      },
      maskURI: mask
    })*/

    // 投影加纹理
    /* this.init({ imageUrl: opacity1, width: 695, height: 649, imgWidth: 695, imgHeight: 649, left: 0, top: 0 }, 'shadowTexture', {
       texture: {
         mode: 'repeat',
         uri: 'https://st0.dancf.com/02/material_uploader/202010120632-bbd5.jpg?x-oss-process=image/resize,w_132,h_132,m_fill/interlace,1,image/format,webp'
       },
       shadow: {
         dx: 10,
         dy: 10,
         blur: 20,
         color: 'red'
       }
     })*/

     /* const url = 'https://st0.dancf.com/02/material_uploader/202010150436-5543.png'
     // width 800 height 800
     this.init({
       imageUrl: url,
       width: 800,
       height: 800,
       imgWidth: 800,
       imgHeight: 800,
       top: 0,
       left: 0
     }, 'shadow', {
       shadow: {
         dx: -10,
         dy: -10,
         blur: 50,
         color: 'red'
       }
     }, [
       {
         dx: 100,
         dy: 100,
         type: 'strokeAll',
         shadow: {
           dx: 10,
           dy: 10,
           blur: 20,
           color: '#333'
         },
         stroke: {
           type: '', // outer
           width: 10,
           color: '#3eef00'
         }
       },
       {
         dx: -150,
         dy: -150,
         type: 'strokeAll',
         gradient: {
           type: 'linear',
           colors: ['blue', '#fff', 'red'],
           positions: [10, 50, 89],
           direction: -90
         },
         shadow: {
           dx: -20,
           dy: -10,
           blur: 20,
           color: '#333'
         },
         stroke: {
           type: 'outer', // outer
           width: 20,
           color: '#3eef00'
         }
       }
     ])*/

    // const url = 'https://shejimao-test.oss-cn-huhehaote.aliyuncs.com/template/3973896240316480/images/f7088bd6-e89c-43ab-1e95-5878e97569c8.png'
     const url = opacity1
    this.init({ imageUrl: url, width: 695, height: 649, imgWidth: 695, imgHeight: 649, left: 0, top: 0 }, '', {
      shadow: {
        dx: 0,
        dy: 0,
        blur: 10,
        color: 'red'
      }
    },
    [
      {
        dx: 20,
        dy: 20,
        texture: {
          mode: 'repeat',
          uri: 'https://st0.dancf.com/02/material_uploader/202010120632-bbd5.jpg?x-oss-process=image/resize,w_132,h_132,m_fill/interlace,1,image/format,webp'
        },
        type: 'texture'
      }
      /* {
        dx: 129,
        dy: 360,
        gradient: {
          colors: ['#0b01b8ff', '#fdfa03ff', '#0b02aaff'],
          positions: [0, 50, 89.990234375],
          direction: -90
        },
        type: 'gradient'
      },
      {
        dx: -10,
        dy: -231,
        shadow: {
          dx: 132.02524267262202,
          dy: 19.53655642446369,
          blur: 18,
          color: '#6d578aff'
        },
        stroke: {
          color: '#59f330ff',
          width: 16,
          type: 'center'
        },
        type: 'strokeAll'
      }*/
    ])
  },
  methods: {
    canvasDraw(imageUrl, { sx, sy, sWidth, sHeight, x, y, width, height }) {
      const canvas = document.getElementById('canvas')
      canvas.width = width
      canvas.height = height
      const ctx = canvas.getContext('2d')
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      const image = new Image()
      image.src = imageUrl
      image.crossOrigin = ''
      image.onload = () => {
        ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height)
      }
    },
    getImgStyle(imageSrc, callback) {
      const img = new Image()
      img.src = imageSrc
      img.onload = function() {
        callback({ width: img.width, height: img.height })
      }
    },
    getEffect(ctx, type = 'source', image) {
      if (type === 'source') {
        ctx.drawImage(image, 0, 0, 300, 300)
        ctx.globalCompositeOperation = 'source-in'
        this.setGradient(ctx, 'linear', {
            x1: 300,
            y1: 300
          },
          [
            { percentage: 0, color: 'blue' },
            { percentage: 1, color: 'red' }
          ],
          {
            width: 300,
            height: 300
          })
      }
      if (type === 'destination') {
        this.setGradient(ctx, 'linear', {
            x1: 300,
            y1: 300
          },
          [
            { percentage: 0, color: 'blue' },
            { percentage: 1, color: 'red' }
          ],
          {
            width: 300,
            height: 300
          })
        ctx.globalCompositeOperation = 'destination-in'
        ctx.drawImage(image, 0, 0, 300, 300)
      }
    },
    handleStrokeShadow(effect, { x, y, width, height, newWidth, newHeight }) {
      let leftOffset = 0
      let topOffset = 0
      let rightOffset = 0
      let bottomOffset = 0
      if (effect.shadow) {
        const { dx, dy, blur } = effect.shadow
        newWidth = width + Math.abs(dx) + blur
        newHeight = height + Math.abs(dy) + blur
        rightOffset = dx + blur
        bottomOffset = dy + blur
        leftOffset = blur - dx > 0 ? blur - dx : 0
        topOffset = blur - dy > 0 ? blur - dy : 0
        if (dx < 0) {
          x = Math.abs(dx)
          leftOffset = x + blur
          rightOffset = blur - x > 0 ? blur - x : 0
          x = blur - dx
        }
        if (dy < 0) {
          y = Math.abs(dy)
          topOffset = y + blur
          bottomOffset = blur - y > 0 ? blur - y : 0
          y = blur - dy
        }
        if (Math.abs(dx) < blur) {
          newWidth = width + blur * 2
          x = blur - dx
        }
        if (Math.abs(dy) < blur) {
          newHeight = height + blur * 2
          y = blur - dy
        }
      }

      if (effect.stroke) {
        const { width, type } = effect.stroke
        if (type === 'outer') {
          if (leftOffset < width) {
            newWidth += width - leftOffset
            x += width - leftOffset
            leftOffset = width
          }
          if (topOffset < width) {
            newHeight += width - topOffset
            y += width - topOffset
            topOffset = width
          }
          if (rightOffset < width) {
            newWidth += width - rightOffset
            rightOffset = width
          }
          if (bottomOffset < width) {
            newHeight += width - bottomOffset
            bottomOffset = width
          }
        } else {
          if (leftOffset < width / 2) {
            newWidth += width / 2 - leftOffset
            x += width / 2 - leftOffset
            leftOffset = width / 2
          }
          if (topOffset < width / 2) {
            newHeight += width / 2 - topOffset
            y += width / 2 - topOffset
            topOffset = width / 2
          }
          if (rightOffset < width / 2) {
            newWidth += width / 2 - rightOffset
            rightOffset = width / 2
          }
          if (bottomOffset < width / 2) {
            newHeight += width / 2 - bottomOffset
            bottomOffset = width / 2
          }
        }
      }

      return {
        x, y, newWidth, newHeight,
        offset: {
          leftOffset, rightOffset, topOffset, bottomOffset
        }
      }
    },
    updateEffectArr(effectArr, width, height) {
      const positionArr = []
      if (effectArr.length > 0) {
        effectArr.forEach(item => {
          let newWidth = width
          let newHeight = height
          let x = 0
          let y = 0

          const newData = this.handleStrokeShadow(item, { x, y, width, height, newWidth, newHeight })
          x = newData.x
          y = newData.y
          newWidth = newData.newWidth
          newHeight = newData.newHeight

          console.log(x, y, newWidth, newHeight, 'new')
          positionArr.push({
            width: newWidth,
            height: newHeight,
            x,
            y,
            type: item.type,
            dx: item.dx,
            dy: item.dy,
            effect: item,
            ...newData.offset
          })
        })
      }
      return positionArr
    },
    getOffset(positionArr) {
      const maxLeft = Math.max(...positionArr.map(item => {
        return item.leftOffset - item.dx
      }))
      const maxTop = Math.max(...positionArr.map(item => {
        return item.topOffset - item.dy
      }))
      const maxRight = Math.max(...positionArr.map(item => {
        return item.rightOffset + item.dx + item.x
      }))
      const maxBottom = Math.max(...positionArr.map(item => {
        return item.bottomOffset + item.dy + item.y
      }))
      return {
        maxLeft,
        maxTop,
        maxRight,
        maxBottom
      }
    },
    getNewPosition({ newWidth, newHeight, x, y }, { leftOffset, rightOffset, topOffset, bottomOffset }, { maxLeft, maxTop, maxRight, maxBottom }) {
      console.log(x, y, '456')
      console.log(leftOffset, maxLeft, rightOffset, maxRight, newWidth)
      if (leftOffset < maxLeft || rightOffset < maxRight) {
        if (leftOffset < maxLeft) {
          newWidth += maxLeft - leftOffset
          x += maxLeft - leftOffset
        }
        if (rightOffset < maxRight) {
          newWidth += maxRight - rightOffset
        }
      }
      if (topOffset < maxTop || bottomOffset < maxBottom) {
        if (topOffset < maxTop) {
          newHeight += maxTop - topOffset
          y += maxTop - topOffset
        }
        if (bottomOffset < maxBottom) {
          newHeight += maxBottom - bottomOffset
        }
      }
      return {
        newWidth,
        newHeight,
        x,
        y
      }
    },
    /**
     * type: String shadow || gradient || texture || stroke || shadowGradient || shadowTexture
     *  effect = {
     *    shadow: {
     *      dx: 0,
            dy: 0,
            blur: 0,
            color: ''
     *    },
     *    gradient: {
     *      type: '',
            colors: [],
            positions: [],
            direction: 0
     *      },
     *      texture: {
     *        mode: '',
     *        uri: ''
     *      },
     *      stroke: {
     *        type: '',
     *        width: 0,
     *        color: ''
     *      }
     *  }
     */
    init({ imageUrl = '', width = 0, height = 0, imgWidth = 0, imgHeight = 0, left = 0, top = 0 }, type, effect, effectArr = []) {
      const canvas = document.getElementById('canvas')
      let x = 0
      let y = 0
      let newWidth = width
      let newHeight = height

      const newData = this.handleStrokeShadow(effect, { x, y, width, height, newWidth, newHeight })
      x = newData.x
      y = newData.y
      newWidth = newData.newWidth
      newHeight = newData.newHeight

      const positionArr = this.updateEffectArr(effectArr, width, height)
      const { maxLeft, maxTop, maxRight, maxBottom } = this.getOffset(positionArr)
      const newPosition = this.getNewPosition({ newWidth, newHeight, x, y }, newData.offset, { maxLeft, maxTop, maxRight, maxBottom })
      newWidth = newPosition.newWidth
      newHeight = newPosition.newHeight
      x = newPosition.x
      y = newPosition.y

      console.log(x, y, '123')
      canvas.width = Math.ceil(newWidth)
      canvas.height = Math.ceil(newHeight)
      const ctx = canvas.getContext('2d')
      ctx.clearRect(0, 0, width, height)
      const image = new Image()
      image.src = imageUrl + '?time=' + new Date().valueOf()
      image.crossOrigin = ''
      image.onload = () => {
        if (effectArr.length > 0) {
          positionArr.forEach(item => {
            const canvasChild = document.createElement('canvas')
            canvasChild.width = item.width
            canvasChild.height = item.height
            const ctxChild = canvasChild.getContext('2d')
            this.handleCanvas(ctxChild, item.type,
              { image, x: item.x, y: item.y, width, height, sx: left, sy: top, sWidth: width, sHeight: height },
              item.effect, () => {
                ctx.drawImage(canvasChild, x + item.dx, y + item.dy, item.width, item.height)
              })
          })
        }
        this.handleCanvas(ctx, type, {
          image,
          x,
          y,
          width,
          height,
          sx: left,
          sy: top,
          sWidth: width,
          sHeight: height
        }, effect)
        canvas.toBlob((blob) => {
          const url = (window.URL) ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob)
          console.log(url)
        })
      }
    },
    async handleCanvas(ctx, type, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect, callBack) {
      console.log(type)
      if (effect.maskURI && effect.maskURI !== '') {
        await this.imageMask(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.maskURI).then(canvasElement => {
          image = canvasElement
        })
      }
      if (type === '') {
        ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height)
      }
      if (type === 'shadow') {
        this.imgShadow(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect.shadow)
      }
      if (type === 'gradient') {
        this.imgGradient(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect.gradient)
      }
      if (type === 'texture') {
        await this.imgTexture(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect.texture)
        callBack()
        console.log('122222222222222222222222')
      }
      if (type === 'stroke') {
        this.imgStroke(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect.stroke)
      }
      if (type === 'shadowGradient') {
        this.imgShadowGradient(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect)
      }
      if (type === 'shadowTexture') {
        this.imgShadowTexture(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect)
      }
      if (type === 'strokeAll') {
        this.imgStrokeAll(ctx, { image, x, y, width, height, sx, sy, sWidth: width, sHeight: height }, effect)
      }
    },
    // 设置投影
    setShadow(ctx, { shadowColor = 'transparent', shadowBlur = 0, shadowOffsetX = 0, shadowOffsetY = 0 }) {
      ctx.shadowColor = shadowColor
      ctx.shadowBlur = shadowBlur
      ctx.shadowOffsetX = shadowOffsetX
      ctx.shadowOffsetY = shadowOffsetY
    },
    // 设置渐变
    setGradient(ctx, type, { x0 = 0, y0 = 0, r0 = 0, x1 = 0, y1 = 0, r1 = 0 },
                gradientData = [{
                  percentage: 1,
                  color: 'transparent'
                }],
                { x = 0, y = 0, width = 0, height = 0 }, rotate = 0) {
      let gradient
      if (type === 'linear') {
        const angle = rotate * Math.PI / 180
        const centerX = (x1 - x0) / 2
        const centerY = (y1 - y0) / 2
        const halfGradientLineLength = (Math.abs((x1 - x0) * Math.cos(angle)) + Math.abs((y1 - y0) * Math.sin(angle))) / 2

        const startX = centerX - Math.cos(angle) * halfGradientLineLength
        const startY = centerY + Math.sin(angle) * halfGradientLineLength

        const endX = centerX + Math.cos(angle) * halfGradientLineLength
        const endY = centerY - Math.sin(angle) * halfGradientLineLength
        gradient = ctx.createLinearGradient(startX, startY, endX, endY)
      }
      if (type === 'radial') {
        gradient = ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)
      }
      gradientData.forEach(item => {
        gradient.addColorStop(item.percentage, item.color)
      })
      ctx.fillStyle = gradient
      ctx.fillRect(x, y, width, height)
    },
    // 设置纹理
    setTexture(ctx, { mode, uri }, { x = 0, y = 0, width = 0, height = 0 }) {
      return new Promise(resolve => {
        const img = new Image()
        img.src = uri
        img.crossOrigin = ''
        img.onload = () => {
          const textureCanvas = document.createElement('canvas')
          textureCanvas.width = img.width
          textureCanvas.height = img.height
          textureCanvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height)
          let type = 'no-repeat'
          if (/repeat/.test(mode)) {
            type = 'repeat'
          }
          ctx.fillStyle = ctx.createPattern(textureCanvas, type)
          ctx.fillRect(x, y, width, height)
          resolve()
        }
      })
    },
    imageMask(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, url) {
      return new Promise(resolve => {
        const img = new Image()
        img.src = url + '?time=' + new Date().valueOf()
        img.crossOrigin = ''
        img.onload = () => {
          const maskCanvas = document.createElement('canvas')
          maskCanvas.width = width
          maskCanvas.height = height
          maskCanvas.style.width = '300px'
          maskCanvas.style.marginLeft = '400px'
          const maskCtx = maskCanvas.getContext('2d')
          maskCtx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, width, height)
          maskCtx.globalCompositeOperation = 'destination-in'
          maskCtx.drawImage(img, 0, 0, width, height)
          resolve(maskCanvas)
        }
      })
    },
    // 描边
    imgStroke(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, stroke) {
      let strokeWidth = stroke.width
      if (stroke.type === 'outer') {
        strokeWidth *= 2
      }
      const halfStrokeWidth = strokeWidth / 2
      const colorArr = this.getColorArr(stroke.color)

      const strokeCanvas = document.createElement('canvas')
      strokeCanvas.width = width + strokeWidth
      strokeCanvas.height = height + strokeWidth
      const strokeCtx = strokeCanvas.getContext('2d')
      strokeCtx.drawImage(image, sx, sy, sWidth, sHeight, halfStrokeWidth, halfStrokeWidth, width, height)

      const imgData = strokeCtx.getImageData(0, 0, width + strokeWidth, height + strokeWidth)

      // 用于读取图片 通过id 读取img、canvas的img值。
      // const imgMat = window.cv.imread(image)
      // 通过 canvas 返回的图片的值进行读取
      const imgMat = window.cv.matFromImageData(imgData)
      const splitMatList = new window.cv.MatVector()
      // 对图片数据进行切割，切割成4份、3份或者是1份（根据图片类型来）
      window.cv.split(imgMat, splitMatList)
      if (splitMatList.size() === 4) {
        const processMat = splitMatList.get(3)
        // 对数据进行过滤
        window.cv.threshold(processMat, processMat, 100, 255, window.cv.THRESH_BINARY)

        const contours = new window.cv.MatVector()
        const hierarchy = new window.cv.Mat()
        // 寻找轮郭
        window.cv.findContours(processMat, contours, hierarchy, window.cv.RETR_TREE, window.cv.CHAIN_APPROX_SIMPLE)
        // 生成描边路径数据
        // let dst = window.cv.Mat.zeros(imgMat.cols, imgMat.rows, window.cv.window.cv_8UC4)
        for (let i = 0; i < contours.size(); ++i) {
          // let color = new window.cv.Scalar(Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255), 255);
          const color = new window.cv.Scalar(colorArr[0], colorArr[1], colorArr[2], 255)
          window.cv.drawContours(imgMat, contours, i, color, strokeWidth, window.cv.LINE_8, hierarchy, 100)
        }
      }
      const newImgData = new ImageData(new Uint8ClampedArray(imgMat.data), imgMat.cols, imgMat.rows)
      strokeCtx.putImageData(newImgData, 0, 0)
      if (stroke.type === 'outer') {
        strokeCtx.drawImage(image, sx, sy, sWidth, sHeight, halfStrokeWidth, halfStrokeWidth, width, height)
      }
      ctx.drawImage(strokeCanvas, x - halfStrokeWidth, y - halfStrokeWidth, width + strokeWidth, height + strokeWidth)
      imgMat.delete()
    },
    imgShadow(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, { dx = 0, dy = 0, blur = 0, color = 'transparent' }) {
      this.setShadow(ctx, { shadowColor: color, shadowOffsetX: dx, shadowOffsetY: dy, shadowBlur: blur })
      ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height)
      ctx.save()
      this.setShadow(ctx, {})
    },
    imgGradient(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, { type = 'linear', colors = [], positions = [], direction = 0 }) {
      ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height)
      ctx.globalCompositeOperation = 'source-in'
      const gradientData = []
      colors.forEach((color, index) => {
        gradientData.push({
          percentage: positions[index] / 100,
          color: color
        })
      })
      this.setGradient(ctx, type, {
          x0: x,
          y0: y,
          x1: width,
          y1: height
        },
        gradientData,
        {
          x,
          y,
          width,
          height
        },
        direction + 90)
      ctx.save()
      ctx.globalCompositeOperation = 'source-over'
    },
    imgTexture(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, { mode, uri }) {
      return new Promise(resolve => {
        ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height)
        ctx.globalCompositeOperation = 'source-in'
        this.setTexture(ctx, { mode, uri }, { x, y, width, height }).then(() => {
          // ctx.save()
          // 用于恢复默认的 globalCompositeOperation 属性，如果不恢复则会影响后面的元素
          ctx.globalCompositeOperation = 'source-over'
          resolve()
        })
      })
    },
    imgShadowGradient(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      const { color, dx, dy, blur } = effect.shadow
      this.setShadow(ctx, { shadowColor: color, shadowOffsetX: dx, shadowOffsetY: dy, shadowBlur: blur })
      const canvasImg = document.createElement('canvas')
      canvasImg.width = width
      canvasImg.height = height
      const ctxImg = canvasImg.getContext('2d')
      this.imgGradient(ctxImg, { image, x: 0, y: 0, width: width, height, sx, sy, sWidth, sHeight }, effect.gradient)
      ctx.drawImage(canvasImg, x, y, width, height)
    },
    async imgShadowTexture(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      const { color, dx, dy, blur } = effect.shadow
      this.setShadow(ctx, { shadowColor: color, shadowOffsetX: dx, shadowOffsetY: dy, shadowBlur: blur })
      const canvasImg = document.createElement('canvas')
      canvasImg.width = width
      canvasImg.height = height
      const ctxImg = canvasImg.getContext('2d')
      await this.imgTexture(ctxImg, {
        image,
        x: 0,
        y: 0,
        width: width,
        height,
        sx,
        sy,
        sWidth,
        sHeight
      }, effect.texture)
      ctx.drawImage(canvasImg, x, y)
    },
   /* imgStrokeShadow(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      this.imgShadow(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.shadow)
      this.imgStroke(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.stroke)
    },
    imgStrokeGradient(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      this.imgGradient(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.gradient)
      const gradientData = ctx.getImageData(x, y, width, height)
      const gradientCanvas = document.createElement('canvas')
      gradientCanvas.width = width
      gradientCanvas.height = height
      gradientCanvas.getContext('2d').putImageData(gradientData, 0, 0)
      this.imgStroke(ctx, { image: gradientCanvas, x, y, width, height, sx, sy, sWidth, sHeight }, effect.stroke)
    },
    async imgStrokeTexture(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      await this.imgTexture(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.texture)
      const gradientData = ctx.getImageData(x, y, width, height)
      const gradientCanvas = document.createElement('canvas')
      gradientCanvas.width = width
      gradientCanvas.height = height
      gradientCanvas.getContext('2d').putImageData(gradientData, 0, 0)
      this.imgShadow(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.shadow)
      this.imgStroke(ctx, { image: gradientCanvas, x, y, width, height, sx, sy, sWidth, sHeight }, effect.stroke)
    },*/
    async imgStrokeAll(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect) {
      let newImage = image
      if (effect.gradient) {
        this.imgGradient(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.gradient)
      }
      if (effect.texture) {
        await this.imgTexture(ctx, { image, x, y, width, height, sx, sy, sWidth, sHeight }, effect.texture)
      }
      if (effect.gradient || effect.texture) {
        const gradientData = ctx.getImageData(x, y, width, height)
        const gradientCanvas = document.createElement('canvas')
        gradientCanvas.width = width
        gradientCanvas.height = height
        gradientCanvas.getContext('2d').putImageData(gradientData, 0, 0)
        newImage = gradientCanvas
      }
      if (effect.shadow) {
        this.imgShadow(ctx, { image: newImage, x, y, width, height, sx, sy, sWidth, sHeight }, effect.shadow)
      }
      this.imgStroke(ctx, { image: newImage, x, y, width, height, sx, sy, sWidth, sHeight }, effect.stroke)
    },
    getColorArr(color) {
      const val = color.slice(1)
      const varArr = val.split('')
      const colorArr = []
      if (val.length === 3 || val.length === 4) {
        varArr.forEach(item => {
          colorArr.push(parseInt(item + item + '', 16))
        })
      }
      if (val.length === 6 || val.length === 8) {
        varArr.forEach((item, index) => {
          if (index !== 0 && index % 2 === 1) {
            colorArr.push(parseInt(val.slice(index - 1, index + 1), 16))
          }
        })
      }
      if (colorArr.length === 3) {
        colorArr[3] = 255
      }
      return colorArr
    }
  }
}
</script>

<style scoped>

</style>
